Skip to content

polish: improve UI feel across the board#107

Merged
TerrifiedBug merged 2 commits intomainfrom
ui/interface-polish
Mar 23, 2026
Merged

polish: improve UI feel across the board#107
TerrifiedBug merged 2 commits intomainfrom
ui/interface-polish

Conversation

@TerrifiedBug
Copy link
Copy Markdown
Owner

Systematic UI polish pass applying interface-feel-better principles across 37 files. No functional changes, no new dependencies.

Changes

Transitions

  • Replace all transition-all with specific properties (button, switch, tabs, sidebar, theme toggle, analytics progress bars) to avoid animating layout-triggering properties

Tactile Feedback

  • Add active:scale-[0.96] press feedback to all Button variants (except link)

Tabular Numbers

  • Add tabular-nums to every dynamically updating number (~20 files) — dashboard KPIs, summary cards, uptime percentages, flow node metrics, log timestamps, chart tooltips, alert values, backup sizes

Typography

  • text-wrap: balance on headings (CardTitle, DialogTitle, PageHeader, EmptyState, auth layout, not-found)
  • text-wrap: pretty on descriptions (CardDescription, DialogDescription, PageHeader, EmptyState, query-error, auth layout, not-found)

Surfaces

  • Fix concentric border radius on flow nodes — overflow-hidden on parent, remove inner rounded-t-lg
  • Add layered box-shadow to Card for natural depth (light + dark variants)
  • Add subtle outline to AvatarImage for edge definition against matching backgrounds

Interactions

  • Expand hit areas on small icon buttons (dashboard tab edit/delete, update banner dismiss) with pseudo-element technique
  • Add background-color, color to sidebar menu button transitions for smoother hover

Liveness

  • Add optional pulse prop to StatusDot with CSS keyframe animation (respects prefers-reduced-motion)

Verification

  • tsc --noEmit
  • eslint src/
  • vitest run — 105/105 tests pass ✓

dependabot bot and others added 2 commits March 23, 2026 20:25
…dates

Bumps the npm_and_yarn group with 2 updates in the / directory: [next](https://github.com/vercel/next.js) and [flatted](https://github.com/WebReflection/flatted).


Updates `next` from 16.1.6 to 16.1.7
- [Release notes](https://github.com/vercel/next.js/releases)
- [Changelog](https://github.com/vercel/next.js/blob/canary/release.js)
- [Commits](vercel/next.js@v16.1.6...v16.1.7)

Updates `flatted` from 3.4.1 to 3.4.2
- [Commits](WebReflection/flatted@v3.4.1...v3.4.2)

---
updated-dependencies:
- dependency-name: next
  dependency-version: 16.1.7
  dependency-type: direct:production
  dependency-group: npm_and_yarn
- dependency-name: flatted
  dependency-version: 3.4.2
  dependency-type: indirect
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support@github.com>
- Replace all transition-all with specific transition properties to
  avoid animating layout-triggering properties
- Add active:scale-[0.96] to buttons for tactile press feedback
- Add tabular-nums to all dynamically updating numbers (~20 files)
  to prevent layout shift on value changes
- Add text-wrap: balance on headings, text-wrap: pretty on body text
  across Card, Dialog, PageHeader, EmptyState, auth layout, not-found
- Fix concentric border radius on flow nodes (overflow-hidden + remove
  inner rounded-t-lg)
- Add layered box-shadow to Card component for natural depth
- Add subtle outline to AvatarImage for edge definition
- Add optional pulse prop to StatusDot for liveness indication
- Expand hit areas on small icon buttons (dashboard tab actions,
  update banner dismiss) with pseudo-element technique
- Add background-color/color to sidebar menu button transitions
  for smoother hover states
@github-actions github-actions bot added the dependencies Pull requests that update a dependency file label Mar 23, 2026
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Mar 23, 2026

Greptile Summary

A thorough UI polish pass across 37 components applying consistent improvements: specific transition-* properties replacing transition-all, tabular-nums on every dynamically-updating number, text-balance/text-pretty on headings and descriptions, active:scale-[0.96] press feedback on buttons, expanded hit areas via pseudo-elements, a concentric border-radius fix on flow nodes, and a new optional pulse prop on StatusDot. Also includes a Next.js patch bump (16.1.6 → 16.1.7).

  • All transition, tabular-nums, text-balance/pretty, overflow-hidden, shadow, and outline changes are correct and well-scoped.
  • active:scale-[0.96] + active:!scale-100 on the link variant — the !important override is valid and works as intended in Tailwind v4.
  • Hit-area pseudo-elements (before:absolute before:-inset-*) — relative positioning is correctly present on all affected parents.
  • StatusDot pulse animation has a color bug@keyframes status-pulse uses currentColor for the box-shadow color, but StatusDot only sets background-color (via bg-status-*); color is never set to the status hue. CSS animations override regular property declarations, so the shadow-[0_0_0_0_var(--status-*)] Tailwind utilities in pulseStyles are dead code during the animation. The expanding glow ring will render in the inherited foreground text color rather than the intended status color (green/amber/red). Adding text-[var(--status-*)] to each pulseStyles entry is the minimal fix — it sets color without affecting the dot's visible background.

Confidence Score: 4/5

  • Safe to merge after fixing the StatusDot pulse ring color — all other changes are correct and well-executed.
  • 37-file polish pass is clean throughout. The single concrete bug is confined to the new pulse prop on StatusDot: the animation's currentColor resolves to the wrong value, making the glow ring the wrong color. It's a one-line-per-variant fix and has no impact on any other changed code.
  • src/components/ui/status-dot.tsx (pulse color bug) and src/app/globals.css (keyframe using currentColor)

Important Files Changed

Filename Overview
src/components/ui/status-dot.tsx New pulse prop added; animation's currentColor resolves to the inherited text color instead of the status color because the element only sets background-color, not color.
src/app/globals.css Adds @keyframes status-pulse outside the prefers-reduced-motion block; the existing animation-duration: 0.01ms !important guard correctly suppresses it for reduced-motion users. The keyframe's currentColor reference is the root cause of the StatusDot colour bug.
src/components/ui/button.tsx Replaces transition-all with specific properties and adds active:scale-[0.96] press feedback; active:!scale-100 correctly overrides the scale on the link variant.
src/components/ui/card.tsx Adds layered box-shadow for light/dark depth and text-balance/text-pretty to CardTitle/CardDescription — clean, no issues.
src/components/flow/source-node.tsx Concentric border-radius fix: overflow-hidden on the outer container and rounded-t-lg removed from the inner header — correctly clips the header colour to the parent's rounded corners.
src/app/(dashboard)/page.tsx Expands hit areas on edit/delete icon buttons via before:absolute before:-inset-1 pseudo-element technique; relative positioning is correctly applied to parent. tabular-nums added to KPI values.
src/components/ui/sidebar.tsx SidebarRail transition-alltransition-[background-color] and SidebarMenuButton gains background-color,color in its transition list — both changes are correct and intentional.
package.json Patch bump of Next.js from 16.1.6 → 16.1.7 with corresponding lockfile updates; no API changes expected.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[StatusDot pulse=true] --> B{variant?}
    B -->|healthy/degraded/error| C["Apply pulseStyles class\n(shadow-[0_0_0_0_var(--status-*)] + animate-[status-pulse])"]
    B -->|neutral/info| D[No pulse — empty string]

    C --> E["CSS animation runs\n@keyframes status-pulse"]
    E --> F["0%/100%: box-shadow 0 0 0 0 currentColor\n50%: box-shadow 0 0 4px transparent"]

    F --> G{What is currentColor?}
    G -->|Expected| H["var(--status-healthy/degraded/error)\n✅ Status-colored ring"]
    G -->|Actual| I["Inherited text color (foreground)\n❌ Wrong color ring"]

    I --> J["shadow-[0_0_0_0_var(--status-*)] Tailwind\nclass is overridden by animation\n— dead code"]

    style I fill:#ef4444,color:#fff
    style H fill:#22c55e,color:#fff
    style J fill:#f97316,color:#fff
Loading
Prompt To Fix All With AI
This is a comment left during a code review.
Path: src/components/ui/status-dot.tsx
Line: 13-19

Comment:
**Pulse ring renders in the wrong color**

The `@keyframes status-pulse` animation in `globals.css` uses `currentColor` for the box-shadow:

```css
0%, 100% { box-shadow: 0 0 0 0 currentColor; }
50%       { box-shadow: 0 0 0 4px transparent; }
```

CSS animations override regular property declarations, so this keyframe completely replaces the `shadow-[0_0_0_0_var(--status-healthy)]` Tailwind utility on the element. `currentColor` resolves to the CSS `color` property — but `StatusDot` only sets `background-color` (via `bg-status-*`); it never sets `color`. As a result, the expanding ring will be the inherited *text* color (e.g. neutral gray), not the status color (green / amber / red).

The `shadow-[0_0_0_0_var(--status-*)]` entries in `pulseStyles` are dead code while the animation is running.

**Fix:** add `color: var(--status-*)` to the element so that `currentColor` resolves to the right hue:

```suggestion
const pulseStyles: Record<StatusVariant, string> = {
  healthy: "text-[var(--status-healthy)] animate-[status-pulse_2s_ease-in-out_infinite]",
  degraded: "text-[var(--status-degraded)] animate-[status-pulse_2s_ease-in-out_infinite]",
  error: "text-[var(--status-error)] animate-[status-pulse_1.5s_ease-in-out_infinite]",
  neutral: "",
  info: "",
};
```

Setting `color` via `text-[var(--status-*)]` won't change the dot's visible colour (that comes from `background-color`), but it makes `currentColor` resolve to the correct value inside the keyframe.

How can I resolve this? If you propose a fix, please make it concise.

Reviews (1): Last reviewed commit: "polish: improve UI feel across the board" | Re-trigger Greptile

Comment on lines +13 to +19
const pulseStyles: Record<StatusVariant, string> = {
healthy: "shadow-[0_0_0_0_var(--status-healthy)] animate-[status-pulse_2s_ease-in-out_infinite]",
degraded: "shadow-[0_0_0_0_var(--status-degraded)] animate-[status-pulse_2s_ease-in-out_infinite]",
error: "shadow-[0_0_0_0_var(--status-error)] animate-[status-pulse_1.5s_ease-in-out_infinite]",
neutral: "",
info: "",
};
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Pulse ring renders in the wrong color

The @keyframes status-pulse animation in globals.css uses currentColor for the box-shadow:

0%, 100% { box-shadow: 0 0 0 0 currentColor; }
50%       { box-shadow: 0 0 0 4px transparent; }

CSS animations override regular property declarations, so this keyframe completely replaces the shadow-[0_0_0_0_var(--status-healthy)] Tailwind utility on the element. currentColor resolves to the CSS color property — but StatusDot only sets background-color (via bg-status-*); it never sets color. As a result, the expanding ring will be the inherited text color (e.g. neutral gray), not the status color (green / amber / red).

The shadow-[0_0_0_0_var(--status-*)] entries in pulseStyles are dead code while the animation is running.

Fix: add color: var(--status-*) to the element so that currentColor resolves to the right hue:

Suggested change
const pulseStyles: Record<StatusVariant, string> = {
healthy: "shadow-[0_0_0_0_var(--status-healthy)] animate-[status-pulse_2s_ease-in-out_infinite]",
degraded: "shadow-[0_0_0_0_var(--status-degraded)] animate-[status-pulse_2s_ease-in-out_infinite]",
error: "shadow-[0_0_0_0_var(--status-error)] animate-[status-pulse_1.5s_ease-in-out_infinite]",
neutral: "",
info: "",
};
const pulseStyles: Record<StatusVariant, string> = {
healthy: "text-[var(--status-healthy)] animate-[status-pulse_2s_ease-in-out_infinite]",
degraded: "text-[var(--status-degraded)] animate-[status-pulse_2s_ease-in-out_infinite]",
error: "text-[var(--status-error)] animate-[status-pulse_1.5s_ease-in-out_infinite]",
neutral: "",
info: "",
};

Setting color via text-[var(--status-*)] won't change the dot's visible colour (that comes from background-color), but it makes currentColor resolve to the correct value inside the keyframe.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/components/ui/status-dot.tsx
Line: 13-19

Comment:
**Pulse ring renders in the wrong color**

The `@keyframes status-pulse` animation in `globals.css` uses `currentColor` for the box-shadow:

```css
0%, 100% { box-shadow: 0 0 0 0 currentColor; }
50%       { box-shadow: 0 0 0 4px transparent; }
```

CSS animations override regular property declarations, so this keyframe completely replaces the `shadow-[0_0_0_0_var(--status-healthy)]` Tailwind utility on the element. `currentColor` resolves to the CSS `color` property — but `StatusDot` only sets `background-color` (via `bg-status-*`); it never sets `color`. As a result, the expanding ring will be the inherited *text* color (e.g. neutral gray), not the status color (green / amber / red).

The `shadow-[0_0_0_0_var(--status-*)]` entries in `pulseStyles` are dead code while the animation is running.

**Fix:** add `color: var(--status-*)` to the element so that `currentColor` resolves to the right hue:

```suggestion
const pulseStyles: Record<StatusVariant, string> = {
  healthy: "text-[var(--status-healthy)] animate-[status-pulse_2s_ease-in-out_infinite]",
  degraded: "text-[var(--status-degraded)] animate-[status-pulse_2s_ease-in-out_infinite]",
  error: "text-[var(--status-error)] animate-[status-pulse_1.5s_ease-in-out_infinite]",
  neutral: "",
  info: "",
};
```

Setting `color` via `text-[var(--status-*)]` won't change the dot's visible colour (that comes from `background-color`), but it makes `currentColor` resolve to the correct value inside the keyframe.

How can I resolve this? If you propose a fix, please make it concise.

@TerrifiedBug TerrifiedBug merged commit 9ed156d into main Mar 23, 2026
12 checks passed
@TerrifiedBug TerrifiedBug deleted the ui/interface-polish branch March 23, 2026 21:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Pull requests that update a dependency file

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant